#ifndef __tenacitas_log_core__thread_id__h__
#define __tenacitas_log_core__thread_id__h__



/** @file */


/** @todo */

// ==> C++ Headers
#include <thread>
#include <functional>
#include <sstream>

// ==> 3rds Headers

// ==> Our Headers

// ==> Namespaces
using namespace std;

// ==> Macro Constants

// ==> Macro Commands


/** ==> namespace of the organization */
namespace tenacitas {
    /** ==> namespace for the project */
    namespace log {

        namespace core {
            
            // ==> Classes

            /** 

                @nosubgrouping 
            */
            class thread_id {

                // ==> thread_id - Friends

                /** Class allowed to access private members of @p thread_id, in
                    order to perform tests */
                friend class thread_id_tester;

                /** Outout operator */
                friend ostream & operator <<(ostream & p_out,
                                             const thread_id & p_th){
                    p_out << p_th.m_value;
                    return p_out;
                }

            public:

                // ==> thread_id - Public Constructors

                /** Default constructor

                    The value id is defined from the current thread
                */
                thread_id();

                /** copy constructor  */
                thread_id (const thread_id & p_th);

                /** move constructor */
                thread_id(thread_id && p_th);

                /** Destructor */
                ~thread_id( );

                // ==> thread_id - Public Helpers

                std::string str();

                // ==> thread_id - Public Operators

                /** equal-to */
                bool operator ==(const thread_id & p_th) const;

                /** not-equal-to */
                bool operator !=(const thread_id & p_th) const;

                /** greater-than */
                bool operator >(const thread_id & p_th) const;

                /** less-than */
                bool operator <(const thread_id & p_th) const;

                /** copy assignment */
                thread_id & operator = (const thread_id & p_th);

                /** move assignment */
                thread_id & operator = (thread_id && p_th);
            
                /** not allowed */
                void* operator new (std::size_t size)
                    throw (std::bad_alloc) = delete;

                /** not allowed */
                void operator delete (void *p_logger) = delete;

                /** not allowed */
                void *operator new[] (size_t) = delete;

                /** not allowed */
                void operator delete[] (void *) = delete;

            private:

                // ==> thread_id - Private Attributes

                /** The actual value of the id */
                std::hash<std::thread::id>::result_type m_value;
            };
        }
    }
}

// =============================================================================
// I M P L E M E N T A T I O N
// =============================================================================

using namespace tenacitas::log::core;

// -----------------------------------------------------------------------------
inline thread_id::
thread_id() 
    : m_value(std::hash<std::thread::id>()(std::this_thread::get_id())){}

// -----------------------------------------------------------------------------
inline thread_id::
thread_id (const thread_id & p_th)
    :m_value(p_th.m_value){}

// -----------------------------------------------------------------------------
inline thread_id::
thread_id(thread_id && p_th) 
    :m_value(std::move(p_th.m_value)){}

// -----------------------------------------------------------------------------
inline thread_id::
~thread_id( ){m_value = std::hash<std::thread::id>()(thread::id());}//::result_type();}


// -----------------------------------------------------------------------------
inline std::string
thread_id::
str() {
    std::stringstream l_stream;
    l_stream << m_value;
    return l_stream.str();
}

// -----------------------------------------------------------------------------
inline bool
thread_id::
operator ==(const thread_id & p_th) const {return m_value == p_th.m_value;}

// -----------------------------------------------------------------------------
inline bool
thread_id::
operator !=(const thread_id & p_th) const {return m_value != p_th.m_value;}

// -----------------------------------------------------------------------------
inline bool
thread_id::
operator >(const thread_id & p_th) const {return m_value > p_th.m_value;}

// -----------------------------------------------------------------------------
inline bool
thread_id::
operator <(const thread_id & p_th) const{return m_value < p_th.m_value;}


// -----------------------------------------------------------------------------
inline thread_id &
thread_id::
operator = (const thread_id & p_th) {
    if (this != &p_th){
        m_value = p_th.m_value;
    }
    return *this;
}



// -----------------------------------------------------------------------------
inline thread_id &
thread_id::
operator = (thread_id && p_th) {
    if (this != &p_th){
        m_value = std::move(p_th.m_value);
    }
    return *this;
}


#endif
